package cate.game.role.farm.island.po;

import cate.common.table.d.GDIsland;
import cate.common.table.d.GDOperation;
import cate.common.table.farm.island.row.*;
import cate.common.table.item.hero.row.HeroBaseRow;
import cate.game.res.MixRes;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.hero.Hero;
import cate.game.role.farm.island.Island;
import cate.game.role.farm.island.cell.*;
import cate.game.role.farm.island.msg.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.util.collection.ListKit;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

@NoteClass(value = "迷失神庙地图")
public class IslandMap extends RoleDependent {

    private static Logger logger = LoggerFactory.getLogger(IslandMap.class);

    @NoteField(value = "地图ID")
    public int mapTid;

    @NoteField(value = "当前层级ID")
    public int floor;

    @NoteField(value = "通关宝箱是否领取")
    public boolean boxGot;

    @NoteField(value = "关卡信息")
    public List<IslandLevel> levels;

    @NoteField(value = "主角所在坐标")
    public Coordinate coordinate;

    @NoteField(value = "本期的地图id")
    @JsonIgnore
    public Map<Integer, Integer> mapHis;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (levels == null) {
            levels = new ArrayList<>();
        }
        levels.forEach(e -> e.initialize(role.getGame()));
        if (coordinate == null) {
            coordinate = new Coordinate();
        }
        if (mapHis == null){
            mapHis = new HashMap<>();
        }
    }

    @JsonIgnore
    public IslandfloorRow getFloorRow() {
        return role.getGame().table.island.floor.get(floor);
    }

    @JsonIgnore
    public IslandCell getCell(int x) {
        for (IslandLevel level : levels) {
            if (level.level == coordinate.level + 1) {
                return level.getCell(x);
            }
        }
        return null;
    }

    @JsonIgnore
    public IslandLevel getLevel(int level) {
        for (IslandLevel levelPO : levels) {
            if (levelPO.level == level) {
                return levelPO;
            }
        }
        return null;
    }

    public boolean moveAvaible(int next) {
        if (coordinate.level % 2 == 1) {
            if (coordinate.x == 1) {
                return next == 1;
            }
            if (coordinate.x == 2) {
                return next == 1 || next == 2;
            }
            if (coordinate.x == 3) {
                return next == 2;
            }
            return false;
        } else {
            // 当玩家在偶数层
            if (coordinate.x == 1) {
                return next == 1 || next == 2;
            }
            if (coordinate.x == 2) {
                return next == 2 || next == 3;
            }
            return false;
        }
    }

    /**
     * 构建地图
     *
     * @param floor 层数
     */
    public EcResult<Void> buildMap(int floor) {
        clear();
        EcResult<Void> r = new EcResult<>();
        // 清理之前的地图数据
        IslandfloorRow floorRow = role.getGame().table.island.floor.get(floor);
        if (floorRow == null) {
            return r.fail("层级不存在");
        }
        IslandMapGroupRow groupRow = role.getGame().table.island.mapGroup.randomMap(floorRow.mapGroup);
        if (groupRow == null) {
            return r.fail("地图配置不存在");
        }
        this.floor = floor;
        this.mapTid = groupRow.mapTid;
        this.mapHis.put(floor, groupRow.mapTid);
        List<IslandMapLevelRow> levelRows = role.getGame().table.island.mapLevel.getMapDetail(this.mapTid);
        for (IslandMapLevelRow levelRow : levelRows) {
            IslandLevel level = buildLevel(levelRow);
            levels.add(level);
        }
        return r.success();
    }

    /**
     * 构建一层的地图
     *
     * @param row
     */
    private IslandLevel buildLevel(IslandMapLevelRow row) {
        IslandLevel level = new IslandLevel();
        level.initialize(role.getGame());
        level.level = row.level;
        if (GDIsland.CellType.isInitCell(row.c1)) {
            level.addCell(buildCell(row.c1, level.level, 1));
        }
        if (GDIsland.CellType.isInitCell(row.c2)) {
            level.addCell(buildCell(row.c2, level.level, 2));
        }
        if (GDIsland.CellType.isInitCell(row.c3)) {
            level.addCell(buildCell(row.c3, level.level, 3));
        }
        return level;
    }

    private IslandCell buildCell(byte type, int level, int x) {
        try {
            switch (type) {
                case GDIsland.CellType.GUARD:
                case GDIsland.CellType.ELITE_GUARD:
                case GDIsland.CellType.BOSS:
                    return buildGuardCell(type, level).setX(x);
                case GDIsland.CellType.AID_HERO:
                    return buildAidHeroCell().setX(x);
                case GDIsland.CellType.HEAL:
                    return new HealCell().setX(x);
                case GDIsland.CellType.REVIVE:
                    return new ReviveCell().setX(x);
                case GDIsland.CellType.MALL:
                    return buildMallCell().setX(x);
                default:
                    return new BlankCell().setX(x);
            }
        } catch (Exception e) {
            logger.error("迷失神庙建格子异常", e);
            return new BlankCell().setX(x);
        }
    }

    private FightSideCell buildGuardCell(byte type, int level) {
        FightSideCell cell = new FightSideCell(type);
        IslandGuardRow row = role.getGame().table.island.guard.getRow(this.floor, level, type);
        if (row != null) {
            IslandGuardGroupRow guardGroupRow = role.getGame().table.island.guardGroup.randomOne(row.group);
            if (guardGroupRow != null) {
                cell.guardId = row.id;
                cell.guardGroupId = guardGroupRow.id;
                cell.guardLevel = calGuardOneLevel(level, row.difficultCoeff);
                cell.guardTwoLevel = calGuradTwoLevel(cell.guardLevel);
                cell.power = role.getGame().power.calByDynCode(guardGroupRow.instance1, cell.guardLevel);
                if (StringUtils.isNotBlank(guardGroupRow.instance2)) {
                    cell.powerTwo = role.getGame().power.calByDynCode(guardGroupRow.instance2, cell.guardTwoLevel);
                }
            }
        }
        return cell;
    }

    /** 根据守卫id创建一个符诏格子 */
    private GainCell buildGainCell(int guardId, int x) {
        GainCell cell = new GainCell();
        List<Integer> gains = new ArrayList<>();
        IslandGuardRow row = role.getGame().table.island.guard.get(guardId);
        if (row == null || row.gainGroup == 0) {
            return null;
        }
        if (role.getFarm().island.difficulty == GDIsland.Difficulty.NORMAL) {
            for (int i = 1; i <= GDIsland.GAIN_NUM; i++) {
                role.getGame().table.island.gainGroup.randomFuzhao(gains, row.gainGroup);
            }
        } else {
            for (int i = 1; i <= GDIsland.GAIN_NUM; i++) {
                role.getGame().table.island.gainGroup.randomFuzhao(role.getGame().table.island.gain, gains, row.gainGroup);
            }
        }
        cell.guardTid = guardId;
        return (GainCell) cell.setGains(gains).setX(x);
    }

    private AidHeroCell buildAidHeroCell() {
        AidHeroCell cell = new AidHeroCell();
        List<Hero> aidHeros = new ArrayList<>();
        List<IslandAidHeroRow> aidHeroRows;
        // 根据玩家等级最高的英雄来生成援助英雄
        Hero hero = role.getBag().hero.getList().stream()
                        .min(Comparator.comparing((Hero a) -> -a.getEffectiveLevel())
                                        .thenComparing(a -> -a.getTpl(role.getGame()).star))
                        .orElse(null);
        if(hero != null){
            aidHeroRows = role.getGame().table.island.aidHero.randomAllCamps();
            if (CollectionUtils.isNotEmpty(aidHeroRows)) {
                if (aidHeroRows.size() > GDIsland.AID_HERO_NUM) {
                    Collections.shuffle(aidHeroRows);
                    aidHeroRows = ListKit.trimMaxKeepHead(aidHeroRows, GDIsland.AID_HERO_NUM);
                }
                int star = Math.max(5,hero.getTpl(role.getGame()).star);
                for(IslandAidHeroRow row : aidHeroRows){
                    HeroBaseRow heroBaseRow = role.getGame().table.hero.base.getRow(row.protoId,star);
                    if(heroBaseRow == null){
                        continue;
                    }
                    Hero aidHero = new Hero(role, heroBaseRow.id);
                    aidHero.level = hero.getEffectiveLevel();
                    aidHero.grade = hero.getEffectiveGrade();
                    role.getGame().fight.hero.setUpHeroItem(aidHero);
                    aidHero.initialize(role);
                    aidHeros.add(aidHero);
                }
            }
        }
        return cell.setHeros(aidHeros);
    }

    private MallCell buildMallCell() {
        MallCell cell = new MallCell();
        List<Integer> items = new ArrayList<>();
        for (int i = 1; i <= GDIsland.SHOP_ITEM_NUM; i++) {
            IslandShopItemRow row = role.getGame().table.island.shopItem.randomItem();
            if (row != null) {
                items.add(row.id);
            }
        }
        return cell.setItems(items);
    }

    /** 常规操作之后的处理*/
    public void afterAction(int x,int param) {
        IslandLevel level = getLevel(coordinate.level + 1);
        if (level == null) {
            return;
        }
        IslandCell cell = level.getCell(x);
        if (cell == null) {
            return;
        }
        //商店购买完不走
        if (cell.type == GDIsland.CellType.MALL && param >=0) {
            level.cells.removeIf(a -> a.x != x);
            role.sendNow(new IslandLevelUpdateResp(level));
            return;
        }

        switch (cell.type) {
            case GDIsland.CellType.BLANK:
            case GDIsland.CellType.GAIN:
            case GDIsland.CellType.AID_HERO:
            case GDIsland.CellType.HEAL:
            case GDIsland.CellType.REVIVE:
            case GDIsland.CellType.MALL:
            case GDIsland.CellType.BOSS:
            case GDIsland.CellType.GUARD:
            case GDIsland.CellType.ELITE_GUARD:
                level.cells.clear();
                level.cells.add(new BlankCell().setX(x));
                coordinate.move(x);
                role.sendNow(new IslandPositionResp(coordinate));
                break;
            default:
                return;
        }
        role.sendNow(new IslandLevelUpdateResp(level));
    }

    /** 战斗之后的处理 */
    public void afterChallenge(int x, boolean win) {
        IslandLevel level = getLevel(coordinate.level + 1);
        if (level == null) {
            return;
        }
        IslandCell cell = level.getCell(x);
        if (cell == null) {
            return;
        }

        // 判断该守卫是否要产生符诏
        FightSideCell guardCell = (FightSideCell) cell;
        if (win) {
            for (Gain gain : role.getFarm().island.record.gains) {
                gain.onWin();
            }
            level.cells.clear();
            GainCell gainCell = buildGainCell(guardCell.guardId, x);
            if (gainCell != null) {
                level.cells.add(gainCell);
            } else {
                level.cells.add(new BlankCell().setX(x));
                coordinate.move(x);
                role.send(new IslandPositionResp(coordinate));
            }
        } else {
            // 挑战失败的话仅仅删除守卫旁边的两个格子
            level.cells.removeIf(a -> a.x != x);
            // 守卫信息更新
            new IslandGuardResp(coordinate.level + 1, x, guardCell);
        }
        role.sendNow(new IslandLevelUpdateResp(level));
    }

    @JsonIgnore
    public EcResult<Void> getBoxReward() {
        EcResult<Void> r = new EcResult<>();
        if (boxGot) {
            return r.fail("宝箱已领取");
        }
        if (notEnd()) {
            return r.fail("通关后可领取");
        }
        IslandfloorRow row = getFloorRow();
        if (row == null) {
            return r.fail("奖励不存在");
        }
        MixRes reward = new MixRes(row.rewardStr);
        reward.add(role, true, GDOperation.ISLAND_BOX_REWARD);
        boxGot = true;
        // 更新宝箱状态
        role.sendNow(new GetIslandBoxRewardResp(boxGot, reward));
        if (role.getFarm().island.passIsland()) {
            role.getFarm().island.updatePassTimes(row.difficulty);
            role.getHistory().action.passIsland();
            role.getHistory().action.passIslandDifficulty(row.difficulty);
        }
        return r.success();
    }

    /** 查看守卫详情 */
    public EcResult<Void> watchGuardDetail(int level, int x) {
        EcResult<Void> r = new EcResult<>();
        IslandLevel islandLevel = getLevel(level);
        if (islandLevel == null) {
            return r.fail("关卡不存在");
        }
        IslandCell cell = islandLevel.getCell(x);
        if (cell == null) {
            return r.fail("格子不存在");
        }
        if (!GDIsland.CellType.isFightCell(cell.type)) {
            return r.fail("不是守卫格子");
        }
        role.sendNow(new IslandGuardResp(level, x, (FightSideCell) cell));
        return r.success();
    }

    public boolean notEnd() {
        return !end();
    }

    public boolean end(){
        return role.getGame().table.island.mapLevel.getMapDetail(mapTid, coordinate.level + 1) == null;
    }

    private void clear() {
        boxGot = false;
        levels.clear();
        coordinate.setCoorDinate(2, 1);
    }

    /** 地图全量更新 */
    public void noticeUpdate() {
        role.sendNow(new IslandMapResp(this));
    }

    /**
     * 计算胜利分数
     * @return
     */
    public double calcSuccessScore(){
        double score  = 0;
        for (Integer floor : mapHis.keySet()) {
            IslandfloorRow floorRow = role.getGame().table.island.floor.get(floor);
            if(floorRow!=null){
                score+=floorRow.successScore;
            }
        }

        return score;
    }

    /**
     * 计算失败分数
     * @return
     */
    public double calFailScore() {
        double score = 0;
        if (mapHis.isEmpty()) {
            return score;
        }

        //当前层数没打完的
        IslandfloorRow floorRow = role.getGame().table.island.floor.get(floor);
        if (floorRow != null) {
            score += floorRow.failScore * (GDIsland.LEVEL_NUM - coordinate.level);
        }
        //没有解锁的层数
        int diff = GDIsland.FLOOR_NUM - mapHis.keySet().size();
        if (diff > 0) {
            for (int i = 0; i < diff; i++) {
                floorRow = role.getGame().table.island.floor.get(floor + i);
                if (floorRow != null) {
                    score += floorRow.failScore * (GDIsland.LEVEL_NUM - 1);
                }
            }
        }
        return score;
    }

    /**
     * 计算1队守卫等级
     * @param guardCoeff
     * @return
     */
    private int calGuardOneLevel(int level, double guardCoeff) {
        int floorNo = 1;
        IslandfloorRow floorRow = role.getGame().table.island.floor.get(floor);
        if (floorRow != null) {
            floorNo = floorRow.floorNo;
        }
        Island island = role.getFarm().island;
        //玩家英雄等级差
        double roleDiffLevel = island.highestLevel - island.shareLevel;

        if (roleDiffLevel < 0) {
            logger.info("玩家{}迷失神庙等级异常 最高等级={} 共享等级={}", role.getBase().name, island.highestLevel, island.shareLevel);
            roleDiffLevel = 0;
        }
        //总关卡数
        double totalLevel = GDIsland.FLOOR_NUM * GDIsland.LEVEL_NUM;
        //当前关卡数
        double curLevel = level + (floorNo - 1) * GDIsland.LEVEL_NUM;
        //玩家系数
        double roleCoeff = Math.max(GDIsland.ROLE_MIN_COEFF, 1 + island.successScore - island.failScore);
        roleCoeff = Math.min(GDIsland.ROLE_MAX_COEFF, roleCoeff);

        int guardLevel = (int) ((roleDiffLevel / totalLevel * curLevel + island.shareLevel) * roleCoeff * guardCoeff);
        if (guardLevel > GDIsland.MAX_HERO_LEVEL) {
            guardLevel = GDIsland.MAX_HERO_LEVEL;
        }
        return Math.max(guardLevel, 1);
    }

    /**
     *
     * @param guardOneLevel
     * @return
     */
    private int calGuradTwoLevel(int guardOneLevel) {
        double coeff = Math.max(0.6, Math.min(guardOneLevel, 410d) / 410d);
        return Math.max((int) (guardOneLevel * coeff), 1);
    }

}
